Inline 原理与流程
Inline hook 就是在运行的流程中插入跳转指令(call/jmp)来抢夺程序运行流程的一个方法。
在编程中我们常用if else或其他语句来控制程序的流程,而在汇编中使用的是cmp和jmp等指令,
cmp是比较,jmp是无条件跳转。
jmp指令后面跟随一个地址,像这样:jmp 0x1234567
inline hook中用到的就是jmp指令,在c中的函数编译之后函数名实际上就是地址,也就是函数所在的内存位置,假设我们想hook一个函数,就跳转到这个函数的首地址,将他的第一条指令修改为jmp指令,这将会覆盖函数原本存在的指令,jmp的地址就是我们自己写的函数。
在执行我们自己写的函数之后,先执行函数中被我们(jmp)覆盖的指令之后,再次调用jmp指令,跳转回去hook之前的代码中执行,不要忘记备份寄存器。
需要注意的地方
- inline hook 的一般流程:
源程序流 -> jmpIn -> 保存寄存器 -> 具体处理 -> 恢复寄存器 -> jmpOut -> 源程序流
被跳转指令覆盖的代码可以在 jmpIn之后 或者 jmpOut之前 - 被覆盖的指令大小和大于等于5,因为我们要塞进去5个字节(0xE9 + Address)。只要你处理跳转指令覆盖的指令,理论上可以 inline hook 函数中的任意位置。
- x86函数调用的开头一般都是下面这个样子的,能很方便的 inline hook
plaintext
1 | mov edi, edi |
jmp 公式:
高地址向低地址跳 – 向前跳:
E9指令地址(4011d2)减去跳转指令地址(401000)
等于偏移大小,偏移大小取反,加一,减五,就是
E9后面的偏移地址
低地址向高地址跳 – 向后跳:
跳转指令地址(4011C1)减去E9偏移地址(401040)
等于偏移大小,偏移大小减五,就是E9后面的偏移地址
Inline Hook实例分析:
c++
1 |
|
解析过程
把Add函数的前5个字节搬到了 hookProxy的前5个字节。
然后再 Add函数的前5个字节填充跳转到 hookProxy 的跳转指令
在hookProxy的末尾5个字节填充跳转回 Add函数 + 5 的跳转指令
原本 Add 函数的结构是3,被 hook 之后会变成 5
有兴趣的读者可以上机调试一番